<template>
    <el-container>
        <el-main id="map" class="mapClass" ref="mapContainer"
                 style="display: flex;flex-direction: column;width: 100%;height: 100%;">
            <div ref="coordLabel" class="coord-label"></div>
        </el-main>
    </el-container>
</template>

<script>
    import mapboxgl from 'mapbox-gl';
    import * as THREE from 'three';
    import {CSS2DRenderer} from 'three-css2drender';
    import {GET_MAPBOX_MAP} from "../components/map/CreateMap";


    export default {
        data() {
            return {
                map: null,
                scene: new THREE.Scene(),
                camera: new THREE.PerspectiveCamera(75, 1, 0.1, 1000),
                renderer: null,
                labelRenderer: new CSS2DRenderer(),
                raycaster: new THREE.Raycaster(),
                cylinders: new Map(), // 存储动态创建的圆柱体
                currentHoverObj: null
            };
        },
        mounted() {
            this.initMapbox();
        },
        beforeDestroy() {
            this.map.remove();
            this.renderer.dispose();
        },
        methods: {
            // 初始化Mapbox地图
            initMapbox() {
                var that = this;
                this.map = GET_MAPBOX_MAP();
                this.map.on('style.load', () => {
                    // Insert the layer beneath any symbol layer.
                    const layers = this.map.getStyle().layers;
                    const labelLayerId = layers.find(
                        (layer) => layer.type === 'symbol' && layer.layout['text-field']
                    ).id;

                    this.map.addLayer(
                        {
                            'id': 'add-3d-buildings',
                            'source': 'composite',
                            'source-layer': 'building',
                            'filter': ['==', 'extrude', 'true'],
                            'type': 'fill-extrusion',
                            'minzoom': 15,
                            'paint': {
                                'fill-extrusion-color': '#aaa',

                                // Use an 'interpolate' expression to
                                // add a smooth transition effect to
                                // the buildings as the user zooms in.
                                'fill-extrusion-height': [
                                    'interpolate',
                                    ['linear'],
                                    ['zoom'],
                                    15,
                                    0,
                                    15.05,
                                    ['get', 'height']
                                ],
                                'fill-extrusion-base': [
                                    'interpolate',
                                    ['linear'],
                                    ['zoom'],
                                    15,
                                    0,
                                    15.05,
                                    ['get', 'min_height']
                                ],
                                'fill-extrusion-opacity': 0.6
                            }
                        },
                        labelLayerId
                    );
                });
                // this.map.on('load', () => {
                //     this.initThreeLayer();
                //     this.setupEventListeners();
                // });
                this.map.on('load', () => {
                    // Three.js主渲染器
                    that.renderer = new THREE.WebGLRenderer({alpha: true});
                    that.renderer.domElement.style.pointerEvents = 'none';
                    document.getElementById('map').appendChild(that.renderer.domElement);

                    // 坐标标签渲染器
                    that.labelRenderer.domElement.style.position = 'absolute';
                    document.getElementById('map').appendChild(that.labelRenderer.domElement);
                    // 自定义Mapbox图层
                    // const threeLayer = {
                    //     id: 'threejs-layer',
                    //     type: 'custom',
                    //     renderingMode: '3d',
                    //     render: (gl, matrix) => {
                    //         that.camera.projectionMatrix.fromArray(matrix);
                    //         that.renderer.render(that.scene, that.camera);
                    //         that.labelRenderer.render(that.scene, that.camera);
                    //     }
                    // };
                    // this.map.addLayer(threeLayer);
                    this.setupEventListeners();
                });

                this.map.on('click', (e) => {
                    // 当前圆柱体地理位置，及展示在three.js所需参数
                    // 需要放在哪个位置
                    if (e.originalEvent.button === 0) { // 确保是鼠标左键点击
                        const modelOrigin = [e.lngLat.lng, e.lngLat.lat]
                        var modelAltitude = 0;
                        var modelRotate = [Math.PI / 2, 0, 0];
                        var modelScale = 5.41843220338983e-8;
                        let modelTransform = {
                            translateX: mapboxgl.MercatorCoordinate.fromLngLat(modelOrigin, modelAltitude).x,
                            translateY: mapboxgl.MercatorCoordinate.fromLngLat(modelOrigin, modelAltitude).y,
                            translateZ: mapboxgl.MercatorCoordinate.fromLngLat(modelOrigin, modelAltitude).z,
                            rotateX: modelRotate[0],
                            rotateY: modelRotate[1],
                            rotateZ: modelRotate[2],
                            scale: modelScale
                        };
                        this.scene = new THREE.Scene();
                        var that = this;
                        var modelId = '3dmodel-' + Date.now();
                        var customLayer = {
                            id: modelId,
                            type: 'custom',
                            renderingMode: '3d',
                            onAdd: function (map, gl) {
                                // var height = 20; // 圆柱体高度，可以根据需要调整
                                // var radiusInMeters = 5000; // 半径5km
                                var lngLat = [e.lngLat.lng, e.lngLat.lat];
                                // const width = this.$refs.clientWidth;
                                // const height = this.$refs.clientHeight;
                                // 添加圆柱体形状
                                var cylinder = new THREE.CylinderGeometry(50, 50, 200, 32);
                                // 添加材质
                                var materials = new THREE.MeshBasicMaterial({
                                    color: '#fdff6e',
                                    side: THREE.DoubleSide,
                                    opacity: 0.5,
                                    transparent: true
                                });
                                cylinder.userData = {layerId: modelId}
                                var cylinderMesh = new THREE.Mesh(cylinder, materials);
                                // 创建光线
                                var directionalLight = new THREE.DirectionalLight(0xffffff);
                                directionalLight.position.set(0, 0, 100).normalize();
                                that.scene.add(this.directionalLight);
                                that.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
                                // 坐标转换
                                const coord = mapboxgl.MercatorCoordinate.fromLngLat(lngLat);
                                cylinderMesh.position.set(coord.x * 1000, coord.y * 1000, 15);
                                cylinderMesh.userData.id = `cylinder-${Date.now()}`;

                                that.cylinders.set(cylinderMesh.userData.id, cylinderMesh);
                                // gltf加载器
                                that.scene.add(cylinderMesh);
                                // s获取Mapbox GL JS map canvas到three.js中
                                that.renderer = new THREE.WebGLRenderer({
                                    canvas: that.map.getCanvas(),
                                    context: gl
                                });
                                that.renderer.autoClear = false;
                            },
                            render: function (gl, matrix) {
                                // 矩阵坐标转换
                                var rotationX = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(1, 0, 0), modelTransform.rotateX);
                                var rotationY = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0, 1, 0), modelTransform.rotateY);
                                var rotationZ = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0, 0, 1), modelTransform.rotateZ);

                                var m = new THREE.Matrix4().fromArray(matrix);
                                var l = new THREE.Matrix4().makeTranslation(modelTransform.translateX, modelTransform.translateY, modelTransform.translateZ)
                                    .scale(new THREE.Vector3(modelTransform.scale, -modelTransform.scale, modelTransform.scale))
                                    .multiply(rotationX)
                                    .multiply(rotationY)
                                    .multiply(rotationZ);

                                that.camera.projectionMatrix.elements = matrix;
                                that.camera.projectionMatrix = m.multiply(l);
                                // const modelMatrix = new THREE.Matrix4().fromArray(matrix);
                                // this.camera.projectionMatrix = modelMatrix.multiply(this.camera.projectionMatrix);
                                that.renderer.state.reset();
                                that.renderer.render(that.scene, that.camera);
                                //渲染
                                that.map.triggerRepaint();
                            }
                        };
                        this.map.addLayer(customLayer);
                    }
                });
            },

            // 初始化Three.js图层
            initThreeLayer(lngLat) {
                // Three.js主渲染器
                this.renderer = new THREE.WebGLRenderer({alpha: true});
                this.renderer.domElement.style.pointerEvents = 'none';
                document.getElementById('map').appendChild(this.renderer.domElement);

                // 坐标标签渲染器
                this.labelRenderer.domElement.style.position = 'absolute';
                document.getElementById('map').appendChild(this.labelRenderer.domElement);
                var modelAltitude = 0;
                var modelRotate = [Math.PI / 2, 0, 0];
                var modelScale = 5.41843220338983e-8;
                let modelTransform = {
                    translateX: mapboxgl.MercatorCoordinate.fromLngLat(lngLat, modelAltitude).x,
                    translateY: mapboxgl.MercatorCoordinate.fromLngLat(lngLat, modelAltitude).y,
                    translateZ: mapboxgl.MercatorCoordinate.fromLngLat(lngLat, modelAltitude).z,
                    rotateX: modelRotate[0],
                    rotateY: modelRotate[1],
                    rotateZ: modelRotate[2],
                    scale: modelScale
                };

                // 自定义Mapbox图层
                const threeLayer = {
                    id: 'threejs-layer',
                    type: 'custom',
                    renderingMode: '3d',
                    onAdd: this.addCylinder(lngLat),
                    render: (gl, matrix) => {
                        // 矩阵坐标转换
                        var rotationX = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(1, 0, 0), modelTransform.rotateX);
                        var rotationY = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0, 1, 0), modelTransform.rotateY);
                        var rotationZ = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0, 0, 1), modelTransform.rotateZ);

                        var m = new THREE.Matrix4().fromArray(matrix);
                        var l = new THREE.Matrix4().makeTranslation(modelTransform.translateX, modelTransform.translateY, modelTransform.translateZ)
                            .scale(new THREE.Vector3(modelTransform.scale, -modelTransform.scale, modelTransform.scale))
                            .multiply(rotationX)
                            .multiply(rotationY)
                            .multiply(rotationZ);

                        this.camera.projectionMatrix.elements = matrix;
                        this.camera.projectionMatrix = m.multiply(l);
                        this.renderer.state.reset();
                        this.renderer.render(this.scene, this.camera);
                        //渲染
                        this.map.triggerRepaint();
                    }
                };
                this.map.addLayer(threeLayer);
            },

            // 动态创建圆柱体
            addCylinder(lnglat) {
                const geo = new THREE.CylinderGeometry(50, 50, 300, 32);
                // 添加材质
                var materials = new THREE.MeshBasicMaterial({
                    color: '#fdff6e',
                    side: THREE.DoubleSide,
                    opacity: 0.5,
                    transparent: true
                });
                const mesh = new THREE.Mesh(geo, materials);
                // 创建光线
                this.directionalLight = new THREE.DirectionalLight(0xffffff);
                this.directionalLight.position.set(0, -50, 100).normalize();
                this.scene.add(this.directionalLight);
                this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
                // 坐标转换
                const coord = mapboxgl.MercatorCoordinate.fromLngLat(lnglat);
                mesh.position.set(coord.x * 1000, coord.y * 1000, 15);
                mesh.userData.id = `cylinder-${Date.now()}`;

                this.scene.add(mesh);
                this.cylinders.set(mesh.userData.id, mesh);
            },

            // 事件监听设置
            setupEventListeners() {
                // 鼠标移动事件（坐标展示）
                this.map.on('mousemove', (e) => {
                    const mouse = this.normalizeMousePos(e.point);
                    this.raycaster.setFromCamera(mouse, this.camera);

                    const intersects = this.raycaster.intersectObjects([...this.cylinders.values()]);
                    if (intersects.length > 0) {
                        debugger
                        this.showCoordLabel(intersects[0].point);
                        this.currentHoverObj = intersects[0].object;
                    } else {
                        this.hideCoordLabel();
                    }
                });

                // 右键删除事件
                this.map.on('contextmenu', (e) => {
                    debugger;
                    e.preventDefault();
                    const mouse = this.normalizeMousePos(e.point);
                    this.raycaster.setFromCamera(mouse, this.camera);

                    const intersects = this.raycaster.intersectObjects([...this.cylinders.values()]);
                    if (intersects.length > 0) {
                        const obj = intersects.object;
                        this.scene.remove(obj);
                        this.cylinders.delete(obj.userData.id);
                    }
                });
            },

            // 标准化鼠标坐标
            normalizeMousePos({x, y}) {
                const rect = this.renderer.domElement.getBoundingClientRect();
                return new THREE.Vector2(
                    ((x - rect.left) / rect.width) * 2 - 1,
                    -((y - rect.top) / rect.height) * 2 + 1
                );
            },

            // 显示坐标标签
            showCoordLabel(position) {
                const label = this.$refs.coordLabel;
                let l_left = position.x + 'px';
                let l_top = position.y + 'px';
                let l_innerHTML = '坐标' + position.x.toFixed(2) + ',' + position.y.toFixed(2);
                label.style.display = 'block';
                label.style.left = l_left;
                label.style.top = l_top;
                label.innerHTML = l_innerHTML;
            },

            hideCoordLabel() {
                // this.$refs.coordLabel.style.display = 'none';
            },

            lngLatToThreeCoords(lngLat, map, sceneCenter) {
                const mercator = map.project(lngLat);
                const centerMercator = map.project(sceneCenter);
                return new THREE.Vector3(
                    mercator.x - centerMercator.x,
                    0,
                    mercator.y - centerMercator.y
                );
            }

        }
    };
</script>

<style>
    .map-container {
        width: 100%;
        height: 100vh;
        position: relative;
    }

    .coord-label {
        position: absolute;
        background: rgba(0, 0, 0, 0.7);
        color: white;
        padding: 5px 10px;
        border-radius: 3px;
        display: none;
    }
</style>
